package com.example.fuluchou.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.example.fuluchou.common.errorcode.ServiceErrorCodeConstants;
import com.example.fuluchou.common.exception.ServiceException;
import com.example.fuluchou.common.untils.*;
import com.example.fuluchou.controller.param.UserLoginParam;
import com.example.fuluchou.controller.param.UserPasswordLoginParam;
import com.example.fuluchou.controller.param.UserRegisterParam;
import com.example.fuluchou.controller.param.UserVerificationCodeLoginParam;
import com.example.fuluchou.dao.dataobject.Encrypt;
import com.example.fuluchou.dao.dataobject.UserDO;
import com.example.fuluchou.dao.mapper.UserMapper;
import com.example.fuluchou.service.UserService;
import com.example.fuluchou.service.VerificationCodeService;
import com.example.fuluchou.service.dto.UserFindDTO;
import com.example.fuluchou.service.dto.UserLoginDTO;
import com.example.fuluchou.service.dto.UserRegisterDTO;
import com.example.fuluchou.service.enums.UserIdentityEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private VerificationCodeService verificationCodeService;


    @Override
    public UserRegisterDTO register(UserRegisterParam param) {

        //校验注册信息
        checkRegisterInfo(param);

        //加密(加密私密数据 构造dao层请求)
        UserDO userDO = new UserDO();
        userDO.setUserName(param.getName());
        userDO.setEmail(param.getMail());
        userDO.setPassword(param.getPassword());
        // Encrypt 对象在向MySQL数据库存储时，会经过 EncryptHandler 处理，自动加密并且转化为数据库支持类型
        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        userDO.setIdentity(param.getIdentity());
        if(StringUtils.hasText(param.getPassword())) {//验证是否是管理员（有密码并进行加密）
            userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }

        //保存数据
        userMapper.insert(userDO);

        //返回
        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId());
        return userRegisterDTO;
    }


    @Override
    public UserLoginDTO login(UserLoginParam param) {
        UserLoginDTO userLoginDTO;
        //校验参数类型，判断登录方式
        if(param instanceof UserPasswordLoginParam loginParam){
            //手机或者邮箱 登录
            userLoginDTO = LoginByPassword(loginParam);
        }else if(param instanceof UserVerificationCodeLoginParam loginParam){
            //验证码登录
            userLoginDTO = LoginByVerificationCode(loginParam);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NO_EXISTS);
        }
        return userLoginDTO;
    }

    @Override
    public List<UserFindDTO> findUserBaseInfoList(UserIdentityEnum forName){
        String identity = ((null==forName)?null:forName.name());

        List<UserDO> userDOList = userMapper.findUserInfo(identity);
        List<UserFindDTO> userFindDTOList = userDOList.stream()
                .map(userDO -> {
                    UserFindDTO userFindDTO = new UserFindDTO();
                    userFindDTO.setUserId(userDO.getId());
                    userFindDTO.setUserName(userDO.getUserName());
                    userFindDTO.setEmail(userDO.getEmail());
                    userFindDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userFindDTO.setIdentity(userDO.getIdentity());
                    return userFindDTO;
                }).collect(Collectors.toList());
        return userFindDTOList;

    }

    /**
     * 验证码登录
     * @param loginParam
     * @return
     */
    private UserLoginDTO LoginByVerificationCode(UserVerificationCodeLoginParam loginParam) {
        UserDO userDO;
        //1.校验手机号
        if(RegexUtil.checkPhone(loginParam.getLoginMobile())) {
            //手机号校验通过，2.获取用户信息
            userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginMobile()));
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_ERROR);
        }
        //3.校验用户信息、身份
        if(null == userDO){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        }else if(StringUtils.hasText(loginParam.getMandatoryIdentity())
                    && !userDO.getIdentity().equals(loginParam.getMandatoryIdentity())){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        //4.校验验证码

        String code =  verificationCodeService.getVerificationCode(loginParam.getLoginMobile());
        if(null == code){
            throw new ServiceException(ServiceErrorCodeConstants.CODE_IS_EMPTY);
        }else if(!code.equals(loginParam.getVerificationCode())) {
            throw new ServiceException(ServiceErrorCodeConstants.CODE_ERROR);
        }
        //5.生成返回信息，返回JWT
        UserLoginDTO userLoginDTO = new UserLoginDTO();
        Map<String,Object> claim = new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);

        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    /**
     * 密码登录
     * @param loginParam
     * @return
     */
    private UserLoginDTO LoginByPassword(UserPasswordLoginParam loginParam) {
        UserDO userDO;
        //1.校验登录信息
        if(RegexUtil.checkPhone(loginParam.getLoginName())){
            //电话登录
            //2.获取用户信息
            userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));
        }else if(RegexUtil.checkMail(loginParam.getLoginName())){
            //邮箱登录
            //2.获取用户信息
            userDO = userMapper.selectByMail(loginParam.getLoginName());
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_WAY_NO_EXISTS);
        }

        //3.校验用户信息、身份、密码
        if(null == userDO){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        }else if(StringUtils.hasText(loginParam.getMandatoryIdentity())
                    &&!loginParam.getMandatoryIdentity().
                        equalsIgnoreCase(userDO.getIdentity())){
            //用户身份校验不通过
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }else if(StringUtils.hasText(loginParam.getPassword())&&
                !DigestUtil.sha256Hex(loginParam.getPassword()).
                        equalsIgnoreCase(userDO.getPassword())){
            //userDO中密码经过非对称加密算法 SHA256 加密过
            //密码错误
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        //4.生成返回信息，返回JWT
        UserLoginDTO userLoginDTO = new UserLoginDTO();
        Map<String,Object> claim = new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);

        userLoginDTO.setToken(token);

        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    private void checkRegisterInfo(UserRegisterParam param) {
        if (null == param) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        //邮箱格式
        if (!RegexUtil.checkMail(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        //手机号格式
        if (!RegexUtil.checkPhone(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_ERROR);
        }
        //校验身份信息
        if (null == UserIdentityEnum.forName(param.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //校验管理员密码（必填）
        if (param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())
                && !StringUtils.hasText(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }
        //密码校验，>=6位
        if (StringUtils.hasText(param.getPassword())
                && !RegexUtil.checkPassword(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        //校验邮箱占用
        if (checkMailUsed(param.getMail())) {
            throw new ServiceException((ServiceErrorCodeConstants.MAIL_USER));
        }

        //校验手机号占用
        if (checkPhoneUsed(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_USER);
        }

    }

    private boolean checkMailUsed(String mail) {
        if (!StringUtils.hasText(mail)) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_IS_EMPTY);

        }
        int count = userMapper.countByMail(mail);
        return count > 0;
    }

    private boolean checkPhoneUsed(String phoneNumber) {
        if (!StringUtils.hasText(phoneNumber)) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_IS_EMPTY);
        }
        int count = userMapper.countByPhone(new Encrypt(phoneNumber));
        return count > 0;
    }

}
















